/**
 * src/utils/pointsUtils.ts
 * ------------------------------------
 * 积分系统工具
 * 1. PointsUtils：积分添加、使用、查询、过期处理等核心功能
 * 2. PointsTransactionResult：积分交易结果接口
 * 3. 支持积分事务处理，确保数据一致性
 * 4. 会员等级计算、积分倍率、过期处理
 * 5. 订单完成、评价、分享等场景的积分奖励
 * 所有积分相关的业务逻辑都通过此工具类处理
 * 创建日期：2025-08-06
 */
import Taro from '@tarojs/taro'
import { User, Order, PointsTransactionType, PointsTransaction, MemberLevel, PointsExpiration } from '../types'
import { CloudDataManager } from './cloud'
import { errorUtils, ErrorType } from './errorHandler'
import pointsConfig from '../config/pointsConfig'

/**
 * 积分交易结果接口
 * 定义积分操作的结果信息
 */
interface PointsTransactionResult {
  success: boolean;
  transactionId?: string;
  error?: string;
  currentPoints?: number;
}

/**
 * 积分系统工具类
 * 提供完整的积分管理功能，包括积分增减、查询、会员等级计算等
 * 支持事务处理，确保数据一致性
 */
export class PointsUtils {
  /**
   * 添加积分（事务处理）
   * 为用户增加指定数量的积分，并记录交易历史
   * @param userId 用户ID
   * @param points 要添加的积分数量
   * @param type 交易类型（如订单完成、评价、分享等）
   * @param description 交易描述
   * @param referenceId 关联的业务ID（如订单ID）
   * @returns Promise<PointsTransactionResult> 交易结果
   */
  static async addPoints(
    userId: string,
    points: number,
    type: PointsTransactionType,
    description: string,
    referenceId?: string
  ): Promise<PointsTransactionResult> {
    return this.executePointsTransaction(userId, points, type, description, referenceId)
  }

  /**
   * 使用积分（事务处理）
   * 扣除用户指定数量的积分，用于订单抵扣等场景
   * @param userId 用户ID
   * @param points 要使用的积分数量
   * @param type 交易类型
   * @param description 交易描述
   * @param referenceId 关联的业务ID
   * @returns Promise<PointsTransactionResult> 交易结果
   */
  static async usePoints(
    userId: string,
    points: number,
    type: PointsTransactionType,
    description: string,
    referenceId?: string
  ): Promise<PointsTransactionResult> {
    // 验证积分是否足够
    const hasEnough = await this.hasEnoughPoints(userId, points)
    if (!hasEnough) {
      return {
        success: false,
        error: '积分不足'
      }
    }
    
    // 验证积分使用是否符合规则
    if (points < pointsConfig.POINTS_USAGE_LIMITS.MIN_POINTS_TO_USE) {
      return {
        success: false,
        error: `最低使用积分为${pointsConfig.POINTS_USAGE_LIMITS.MIN_POINTS_TO_USE}分`
      }
    }
    
    if (points % pointsConfig.POINTS_USAGE_LIMITS.POINTS_USE_MULTIPLE !== 0) {
      return {
        success: false,
        error: `积分使用必须是${pointsConfig.POINTS_USAGE_LIMITS.POINTS_USE_MULTIPLE}的倍数`
      }
    }
    
    return this.executePointsTransaction(userId, -points, type, description, referenceId)
  }

  /**
   * 执行积分事务
   * 核心的积分变动处理逻辑，确保数据一致性
   * @param userId 用户ID
   * @param points 积分变动（正数为增加，负数为减少）
   * @param type 交易类型
   * @param description 交易描述
   * @param referenceId 关联的业务ID
   * @returns Promise<PointsTransactionResult> 交易结果
   */
  private static async executePointsTransaction(
    userId: string,
    points: number,
    type: PointsTransactionType,
    description: string,
    referenceId?: string
  ): Promise<PointsTransactionResult> {
    // 获取数据库实例
    const db = CloudDataManager.getDB()
    
    try {
      // 使用事务确保原子性
      return await errorUtils.withRetry(async () => {
        // 1. 获取用户当前积分和会员等级
        const user = await CloudDataManager.getUserById(userId)
        if (!user) {
          return {
            success: false,
            error: '用户不存在'
          }
        }
        
        const currentPoints = user.points || 0
        let pointsToAdd = points;
        let multiplier = 1.0;
        
        // 2. 如果是积分奖励类型，应用会员等级倍率
        if (points > 0 && type !== 'admin_adjustment' && type !== 'points_expired') {
          const memberLevel = user.memberLevel || 1;
          const levelConfig = pointsConfig.MEMBER_LEVELS.find(level => level.level === memberLevel);
          if (levelConfig) {
            multiplier = levelConfig.pointsMultiplier;
            pointsToAdd = Math.floor(points * multiplier);
          }
        }
        
        const newPoints = currentPoints + pointsToAdd;
        
        // 3. 检查积分是否会变为负数
        if (newPoints < 0) {
          return {
            success: false,
            error: '积分不足'
          }
        }
        
        // 4. 计算积分过期日期
        let expirationDate: Date | undefined;
        if (points > 0 && pointsConfig.POINTS_EXPIRATION.ENABLED) {
          const memberLevel = user.memberLevel || 1;
          const expirationDays = pointsConfig.POINTS_EXPIRATION.LEVEL_EXPIRATION[memberLevel];
          
          if (expirationDays > 0) {
            expirationDate = new Date();
            expirationDate.setDate(expirationDate.getDate() + expirationDays);
          }
        }
        
        // 5. 创建积分交易记录
        const transaction: Omit<PointsTransaction, 'id'> = {
          userId,
          points: Math.abs(pointsToAdd),
          type,
          isDebit: pointsToAdd < 0,
          description,
          referenceId,
          createdAt: new Date(),
          balanceAfter: newPoints,
          multiplier: multiplier !== 1.0 ? multiplier : undefined,
          expirationDate
        }
        
        // 6. 保存交易记录
        const transactionId = await CloudDataManager.addData('points_transactions', transaction)
        
        // 7. 如果有过期日期，创建积分过期记录
        if (expirationDate && points > 0) {
          const expirationRecord: Omit<PointsExpiration, 'id'> = {
            userId,
            points: pointsToAdd,
            expirationDate,
            isExpired: false,
            transactionId
          }
          
          await CloudDataManager.addData('points_expirations', expirationRecord)
        }
        
        // 8. 更新用户积分和历史累计积分
        const updateData: any = {
          points: newPoints,
          updatedAt: new Date()
        }
        
        // 如果是增加积分，更新历史累计积分
        if (points > 0 && type !== 'admin_adjustment') {
          updateData.totalHistoricalPoints = (user.totalHistoricalPoints || 0) + pointsToAdd
          
          // 检查是否需要升级会员等级
          const newLevel = this.calculateMemberLevel(updateData.totalHistoricalPoints)
          if (newLevel !== (user.memberLevel || 1)) {
            updateData.memberLevel = newLevel
            
            // 如果是升级（而不是降级），发送通知和奖励
            if (newLevel > (user.memberLevel || 1)) {
              // 获取新等级信息
              const newLevelInfo = pointsConfig.MEMBER_LEVELS.find(level => level.level === newLevel)
              
              // 发送会员升级通知
              await CloudDataManager.addData('notifications', {
                userId,
                title: '会员等级升级',
                content: `恭喜您升级为${newLevelInfo?.name || `${newLevel}级会员`}，享受更多权益！`,
                type: 'level_upgrade',
                isRead: false,
                createdAt: new Date()
              })
              
              // 记录升级日志
              await CloudDataManager.addData('user_logs', {
                userId,
                type: 'level_upgrade',
                details: {
                  oldLevel: user.memberLevel || 1,
                  newLevel,
                  totalPoints: updateData.totalHistoricalPoints
                },
                createdAt: new Date()
              })
              
              // 如果配置了升级奖励，可以在这里添加
              // TODO: 实现升级奖励逻辑
            }
          }
        }
        
        await CloudDataManager.updateData('users', userId, updateData)
        
        // 9. 返回成功结果
        return {
          success: true,
          transactionId,
          currentPoints: newPoints
        }
      })
    } catch (error) {
      console.error('积分事务处理失败:', error)
      
      // 记录错误但不抛出，避免中断主流程
      errorUtils.handleError(error, ErrorType.DATABASE, {
        showToast: true,
        data: { userId, points, type, operation: 'pointsTransaction' }
      })
      
      return {
        success: false,
        error: error instanceof Error ? error.message : '积分操作失败'
      }
    }
  }

  /**
   * 获取用户积分交易历史
   * @param userId 用户ID
   * @returns Promise<PointsTransaction[]>
   */
  static async getUserTransactions(userId: string): Promise<PointsTransaction[]> {
    try {
      const transactions = await CloudDataManager.getAllData('points_transactions', { userId })
      return transactions.map(transaction => ({
        ...transaction,
        createdAt: new Date(transaction.createdAt),
        expirationDate: transaction.expirationDate ? new Date(transaction.expirationDate) : undefined
      })).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
    } catch (error) {
      console.error('获取积分交易历史失败:', error)
      return []
    }
  }

  /**
   * 计算订单可使用的最大积分
   * @param totalAmount 订单总金额
   * @param userPoints 用户当前积分
   * @returns number
   */
  static calculateMaxPointsForOrder(totalAmount: number, userPoints: number): number {
    // 积分最多抵扣订单金额的配置比例
    const maxByAmount = Math.floor(totalAmount * pointsConfig.POINTS_USAGE_LIMITS.MAX_DISCOUNT_PERCENTAGE * (1 / pointsConfig.POINTS_EXCHANGE_RATE.POINTS_TO_MONEY))
    // 不能超过用户拥有的积分
    const maxPoints = Math.min(maxByAmount, userPoints)
    // 必须是POINTS_USE_MULTIPLE的倍数
    return Math.floor(maxPoints / pointsConfig.POINTS_USAGE_LIMITS.POINTS_USE_MULTIPLE) * pointsConfig.POINTS_USAGE_LIMITS.POINTS_USE_MULTIPLE
  }

  /**
   * 计算积分抵扣金额
   * @param points 使用的积分
   * @returns number
   */
  static calculateDiscountAmount(points: number): number {
    // 按照配置的兑换比例计算
    return points * pointsConfig.POINTS_EXCHANGE_RATE.POINTS_TO_MONEY
  }

  /**
   * 计算订单可获得的积分
   * @param finalAmount 实际支付金额
   * @returns number
   */
  static calculateOrderPoints(finalAmount: number): number {
    // 按照配置的兑换比例计算
    return Math.floor(finalAmount * pointsConfig.POINTS_EXCHANGE_RATE.MONEY_TO_POINTS)
  }

  /**
   * 处理订单完成时的积分奖励
   * @param order 订单信息
   * @returns Promise<PointsTransactionResult>
   */
  static async processOrderCompletionPoints(order: Order): Promise<PointsTransactionResult> {
    if (!order.userId || order.status !== 'completed') {
      return {
        success: false,
        error: '订单状态不正确'
      }
    }
    
    try {
      // 1. 获取用户信息
      const user = await CloudDataManager.getUserById(order.userId)
      if (!user) {
        return {
          success: false,
          error: '用户不存在'
        }
      }
      
      // 2. 计算基础积分
      const basePoints = this.calculateOrderPoints(order.finalAmount)
      
      // 3. 添加基础积分
      const result = await this.addPoints(
        order.userId,
        basePoints,
        'order_completion',
        `订单完成奖励: ${order.id}`,
        order.id
      )
      
      // 4. 检查是否是首单奖励
      if (!user.firstOrderDate) {
        // 更新用户首单日期
        await CloudDataManager.updateData('users', user.id, {
          firstOrderDate: new Date(),
          lastOrderDate: new Date()
        })
        
        // 添加首单奖励积分
        await this.addPoints(
          order.userId,
          pointsConfig.POINTS_REWARDS.FIRST_ORDER,
          'first_order_bonus',
          `首单额外奖励`,
          order.id
        )
      } else {
        // 5. 检查是否是连续下单
        const lastOrderDate = user.lastOrderDate ? new Date(user.lastOrderDate) : null
        const today = new Date()
        
        // 设置时间为00:00:00以便比较日期
        today.setHours(0, 0, 0, 0)
        
        if (lastOrderDate) {
          lastOrderDate.setHours(0, 0, 0, 0)
          
          const yesterday = new Date(today)
          yesterday.setDate(yesterday.getDate() - 1)
          
          // 如果上次下单是昨天，增加连续下单天数
          if (lastOrderDate.getTime() === yesterday.getTime()) {
            const consecutiveDays = (user.consecutiveOrderDays || 0) + 1
            
            // 更新用户连续下单信息
            await CloudDataManager.updateData('users', user.id, {
              consecutiveOrderDays: consecutiveDays,
              lastOrderDate: new Date()
            })
            
            // 添加连续下单奖励
            await this.addPoints(
              order.userId,
              pointsConfig.POINTS_REWARDS.CONSECUTIVE_ORDER,
              'consecutive_order_bonus',
              `连续下单${consecutiveDays}天奖励`,
              order.id
            )
          } else if (lastOrderDate.getTime() !== today.getTime()) {
            // 如果不是今天也不是昨天，重置连续下单天数
            await CloudDataManager.updateData('users', user.id, {
              consecutiveOrderDays: 1,
              lastOrderDate: new Date()
            })
          }
        } else {
          // 首次记录下单日期
          await CloudDataManager.updateData('users', user.id, {
            consecutiveOrderDays: 1,
            lastOrderDate: new Date()
          })
        }
      }
      
      return result
    } catch (error) {
      console.error('处理订单完成积分失败:', error)
      return {
        success: false,
        error: '积分处理失败'
      }
    }
  }

  /**
   * 处理评价奖励积分
   * @param userId 用户ID
   * @param dishId 菜品ID
   * @returns Promise<PointsTransactionResult>
   */
  static async processRatingPoints(userId: string, dishId: string): Promise<PointsTransactionResult> {
    return this.addPoints(
      userId,
      pointsConfig.POINTS_REWARDS.RATING,
      'rating_bonus',
      `评价奖励: ${dishId}`,
      dishId
    )
  }

  /**
   * 处理分享奖励积分
   * @param userId 用户ID
   * @param shareType 分享类型
   * @returns Promise<PointsTransactionResult>
   */
  static async processSharingPoints(userId: string, shareType: string): Promise<PointsTransactionResult> {
    return this.addPoints(
      userId,
      pointsConfig.POINTS_REWARDS.SHARING,
      'sharing_bonus',
      `分享奖励: ${shareType}`,
      shareType
    )
  }

  /**
   * 处理注册奖励积分
   * @param userId 用户ID
   * @returns Promise<PointsTransactionResult>
   */
  static async processRegistrationPoints(userId: string): Promise<PointsTransactionResult> {
    return this.addPoints(
      userId,
      pointsConfig.POINTS_REWARDS.REGISTRATION,
      'registration_bonus',
      `注册奖励`,
      userId
    )
  }

  /**
   * 检查用户是否有足够积分
   * @param userId 用户ID
   * @param requiredPoints 所需积分
   * @returns Promise<boolean>
   */
  static async hasEnoughPoints(userId: string, requiredPoints: number): Promise<boolean> {
    try {
      const user = await CloudDataManager.getUserById(userId)
      if (!user) return false
      
      const currentPoints = user.points || 0
      return currentPoints >= requiredPoints
    } catch (error) {
      console.error('检查用户积分失败:', error)
      return false
    }
  }

  /**
   * 获取用户当前积分
   * @param userId 用户ID
   * @returns Promise<number>
   */
  static async getUserPoints(userId: string): Promise<number> {
    try {
      const user = await CloudDataManager.getUserById(userId)
      return user?.points || 0
    } catch (error) {
      console.error('获取用户积分失败:', error)
      return 0
    }
  }

  /**
   * 获取用户会员等级信息
   * @param userId 用户ID
   * @returns Promise<{level: MemberLevel, name: string, nextLevel?: {level: MemberLevel, name: string, pointsNeeded: number}}>
   */
  static async getUserMemberInfo(userId: string): Promise<{
    level: MemberLevel,
    name: string,
    pointsMultiplier: number,
    benefits: string[],
    nextLevel?: {
      level: MemberLevel,
      name: string,
      pointsNeeded: number
    }
  }> {
    try {
      const user = await CloudDataManager.getUserById(userId)
      if (!user) {
        throw new Error('用户不存在')
      }
      
      const memberLevel = user.memberLevel || 1
      const totalPoints = user.totalHistoricalPoints || 0
      
      // 获取当前等级信息
      const currentLevelInfo = pointsConfig.MEMBER_LEVELS.find(level => level.level === memberLevel)
      if (!currentLevelInfo) {
        throw new Error('会员等级配置错误')
      }
      
      // 查找下一等级
      const nextLevelInfo = pointsConfig.MEMBER_LEVELS.find(level => level.level === memberLevel + 1)
      
      const result: any = {
        level: memberLevel,
        name: currentLevelInfo.name,
        pointsMultiplier: currentLevelInfo.pointsMultiplier,
        benefits: currentLevelInfo.benefits
      }
      
      // 如果有下一等级，计算还需要多少积分
      if (nextLevelInfo) {
        result.nextLevel = {
          level: nextLevelInfo.level,
          name: nextLevelInfo.name,
          pointsNeeded: nextLevelInfo.minPoints - totalPoints
        }
      }
      
      return result
    } catch (error) {
      console.error('获取用户会员信息失败:', error)
      return {
        level: 1,
        name: '普通会员',
        pointsMultiplier: 1.0,
        benefits: ['基础积分累计']
      }
    }
  }

  /**
   * 计算会员等级
   * @param totalPoints 历史累计积分
   * @returns MemberLevel
   */
  static calculateMemberLevel(totalPoints: number): MemberLevel {
    // 从高到低检查，符合哪个等级的最低积分要求
    for (let i = pointsConfig.MEMBER_LEVELS.length - 1; i >= 0; i--) {
      if (totalPoints >= pointsConfig.MEMBER_LEVELS[i].minPoints) {
        return pointsConfig.MEMBER_LEVELS[i].level as MemberLevel
      }

    }
    return 1 // 默认为普通会员
  }

  /**
   * 处理积分过期
   * @returns Promise<number> 处理的过期积分数量
   */
  static async processExpiredPoints(): Promise<number> {
    try {
      const today = new Date()
      today.setHours(0, 0, 0, 0)
      
      // 查找今天过期的积分
      const expirations = await CloudDataManager.getAllData('points_expirations', {
        isExpired: false,
        expirationDate: { $lt: today }
      }) as PointsExpiration[]
      
      let processedCount = 0
      
      // 处理每个过期记录
      for (const expiration of expirations) {
        // 1. 获取用户当前积分
        const user = await CloudDataManager.getUserById(expiration.userId)
        if (!user) continue
        
        // 2. 扣除过期积分
        const currentPoints = user.points || 0
        const pointsToDeduct = Math.min(currentPoints, expiration.points) // 不能扣成负数
        
        if (pointsToDeduct > 0) {
          // 3. 创建积分过期交易
          await this.executePointsTransaction(
            expiration.userId,
            -pointsToDeduct,
            'points_expired',
            `积分过期`,
            expiration.transactionId
          )
          
          processedCount += pointsToDeduct
        }
        
        // 4. 标记为已过期
        await CloudDataManager.updateData('points_expirations', expiration.id, {
          isExpired: true
        })
      }
      
      return processedCount
    } catch (error) {
      console.error('处理积分过期失败:', error)
      return 0
    }
  }

  /**
   * 格式化交易类型
   * @param type 交易类型
   * @returns string
   */
  static formatTransactionType(type: PointsTransactionType): string {
    const typeMap: Record<PointsTransactionType, string> = {
      order_completion: '订单完成奖励',
      order_payment: '订单积分抵扣',
      admin_adjustment: '管理员调整',
      registration_bonus: '注册奖励',
      referral_bonus: '推荐奖励',
      activity_reward: '活动奖励',
      first_order_bonus: '首单奖励',
      rating_bonus: '评价奖励',
      sharing_bonus: '分享奖励',
      consecutive_order_bonus: '连续下单奖励',
      points_expired: '积分过期'
    }
    
    return typeMap[type] || type
  }

  /**
   * 恢复错误交易
   * @param transactionId 交易ID
   * @returns Promise<boolean>
   */
  static async reverseTransaction(transactionId: string): Promise<boolean> {
    try {
      // 1. 获取原始交易
      const transaction = await CloudDataManager.getData('points_transactions', transactionId) as PointsTransaction
      if (!transaction) {
        return false
      }
      
      // 2. 创建反向交易
      const reversePoints = transaction.isDebit ? transaction.points : -transaction.points
      
      // 3. 执行反向交易
      const result = await this.executePointsTransaction(
        transaction.userId,
        reversePoints,
        'admin_adjustment',
        `交易撤销: ${transaction.description}`,
        transactionId
      )
      
      return result.success
    } catch (error) {
      console.error('撤销积分交易失败:', error)
      return false
    }
  }
}

// 导出工具函数
export const pointsUtils = {
  addPoints: PointsUtils.addPoints,
  usePoints: PointsUtils.usePoints,
  getUserTransactions: PointsUtils.getUserTransactions,
  calculateMaxPointsForOrder: PointsUtils.calculateMaxPointsForOrder,
  calculateDiscountAmount: PointsUtils.calculateDiscountAmount,
  calculateOrderPoints: PointsUtils.calculateOrderPoints,
  processOrderCompletionPoints: PointsUtils.processOrderCompletionPoints,
  processRatingPoints: PointsUtils.processRatingPoints,
  processSharingPoints: PointsUtils.processSharingPoints,
  processRegistrationPoints: PointsUtils.processRegistrationPoints,
  hasEnoughPoints: PointsUtils.hasEnoughPoints,
  getUserPoints: PointsUtils.getUserPoints,
  getUserMemberInfo: PointsUtils.getUserMemberInfo,
  calculateMemberLevel: PointsUtils.calculateMemberLevel,
  processExpiredPoints: PointsUtils.processExpiredPoints,
  formatTransactionType: PointsUtils.formatTransactionType,
  reverseTransaction: PointsUtils.reverseTransaction
} 